/*************************************************************************
    > File Name: Remoted.cpp
	> Author: xuwenlong
	> Mail: myxuan475@126.com 
	> Created Time: 2019年01月30日 星期三 17时01分04秒
 ************************************************************************/
#include "remoted.h"
#include <sys/select.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <utils/shellcmd.h>
#include <sys/time.h>
#include <poll.h>
#include <netinet/in.h>
#include <netdb.h>
#include <base64.h>

#define USE_XFRP

#ifdef USE_XFRP
#ifdef __cplusplus
extern "C" {
#endif
#include <xfrp/xfrpc.h>
#include <xfrp/config.h>
#include <xfrp/login.h>

#ifdef __cplusplus
}
#endif
#include <utils/config.h>
#endif

using namespace std;

Remoted::Remoted(): m_eFlag(TEL_INIT),
    m_flaglock(true),
    m_ackTimer(new Timer("remoted",this)) {
#ifdef TELNET_CUSTOM
    m_iSock = -1;
#endif
}

Remoted::~Remoted()
{
    m_flaglock.Acquire();
    m_eFlag = TEL_END;
    m_flaglock.Release();

    m_ackTimer->Stop();
}

void Remoted::RunTimer()
{
    TelnetDo();
}

void Remoted::TelnetDo()
{
#ifdef USE_XFRP
    AutoLock lock(m_flaglock);
    m_eFlag = TEL_RUN;
    load_config(utils::GetCompletePath("Config.ini").c_str(),
                m_type.c_str(),
                m_hostname.c_str(),
                m_iPort);
    init_login();
    {
        AutoUnlock unlock(m_flaglock);
        xfrpc_loop();
    }while(0);

    free_config();
    m_eFlag = TEL_END;
#else
//    SendCmd(14,"\nHello leo!\n\\>");
    int sock = connect_server("127.0.0.1",23);

    if (sock < 0) {
        Stop();
        return;
    }

    m_eFlag = TEL_RUN;

    struct pollfd pfd[2];

    pfd[0].fd = m_iSock;
    pfd[0].events = POLLIN;
    pfd[1].fd = sock;
    pfd[1].events = POLLIN;

    char buffer[512];
    while (m_eFlag == TEL_RUN && poll(pfd,2,1000) != -1) {
        int rs;
        //read from das server to telnet server
        if (pfd[0].revents & POLLIN) {
            rs = recv(m_iSock,buffer,sizeof(buffer),0);
            if (rs <= 0) {
                close(m_iSock);
                m_iSock = -1;
                break;
            }
            send(sock,buffer,rs,0);
        }
        //read from telnet server to das server
        if (pfd[1].revents & POLLIN) {
            rs = recv(sock,buffer,sizeof(buffer),0);
            if (rs <= 0) {
                close(sock);
                sock = -1;
                break;
            }
            send(m_iSock,buffer,rs,0);
        }
    }
    if (m_iSock != -1)
        close(m_iSock);
    if (sock != -1)
        close(sock);
    m_iSock = -1;
    m_eFlag = TEL_END;
//    SendCmd(16,"\nGoodbye leo!\n\\>");
#endif
}

void Remoted::Stop()
{
#ifdef TELNET_CUSTOM
    if (m_iSock > 0)
        close(m_iSock);
    m_iSock = -1;
#endif
#ifdef USE_XFRP
    xfrpc_exit();

#endif
    m_flaglock.Acquire();
    m_eFlag = TEL_END;
    m_flaglock.Release();
}

DAS_RESULT Remoted::Start(const Json::Value &params)
{
#ifdef USE_XFRP
    Stop();
    m_type = params["type"].asString();
    m_hostname = params["hostname"].asString();
    m_iPort = params["port"].asInt();

#else
    string strip = params["hostname"].asString();
    int port = params["port"].asInt();

    //stop socket
    Stop();

    //restart
    m_iSock = connect_server(strip,port);

    if (m_iSock < 0)
        return DAS_FAILDSET;  
#endif

    m_ackTimer->Start(100,kSingleShot);
    return DAS_SUCCESS;
}

bool Remoted::IsTelneted()
{
    AutoLock lock(m_flaglock);
    return m_eFlag == TEL_RUN;
}

int Remoted::connect_server(const string &host, int port)
{
    struct sockaddr_in addr;
    struct addrinfo *ai;
    struct addrinfo hints;

    memset(&hints,0,sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    char strport[10] = {0};
    sprintf(strport,"%d",port);

    int err;
    if ((err = getaddrinfo(host.c_str(),strport,&hints,&ai)) != 0) {
        LOG_ERR("getaddrinfo error,%s",gai_strerror(err));
        return -1;
    }

    int sock = socket(AF_INET,SOCK_STREAM,0);
    memset(&addr,0,sizeof(addr));
    addr.sin_family = AF_INET;
//    addr.sin_addr.s_addr = inet_addr("192.168.0.236");
//    addr.sin_port = htons(23);
    if (::bind(sock,(struct sockaddr *)&addr,sizeof(addr)) == -1) {
        LOG_ERR("bind error,%s",strerror(errno));
        close(sock);
        freeaddrinfo(ai);
//        SendCmd(16,"\nbind failed!\n\\>");
        return -1;
    }

    if (-1 == connect(sock,ai->ai_addr,ai->ai_addrlen)) {
        LOG_ERR("connect failed,%s",strerror(errno));
        close(sock);
        freeaddrinfo(ai);
        return -1;
    }
    freeaddrinfo(ai);
    return sock;
}
